home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs15.zoo / streambu.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-01  |  15.1 KB  |  705 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1991, 1992 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #define _STREAM_COMPAT
  19. #ifdef __GNUG__
  20. #pragma implementation
  21. #endif
  22. #include <ioprivat.h>
  23. #include <string.h>
  24.  
  25. // Return minimum _pos markers
  26. // Assumes the current get area is the main get area.
  27. long streambuf::_least_marker()
  28. {
  29.     long least_so_far = _egptr - _eback;
  30.     for (register streammarker *mark = _markers;
  31.      mark != NULL; mark = mark->_next)
  32.     if (mark->_pos < least_so_far)
  33.         least_so_far = mark->_pos;
  34.     return least_so_far;
  35. }
  36.  
  37. // Switch current get area from backup buffer to (start of) main get area.
  38.  
  39. void streambuf::switch_to_main_get_area()
  40. {
  41.     char *tmp;
  42.     _flags &= ~_S_IN_BACKUP;
  43.     // Swap _egptr and _other_egptr.
  44.     tmp= _egptr; _egptr= _other_egptr; _other_egptr= tmp;
  45.     // Swap _eback and _other_gbase.    
  46.     tmp= _eback; _eback = _other_gbase; _other_gbase = tmp;
  47.     _gptr = _eback;
  48. }
  49.  
  50. // Switch current get area from main get area to (end of) backup area.
  51.  
  52. void streambuf::switch_to_backup_area()
  53. {
  54.     char *tmp;
  55.     _flags |= _S_IN_BACKUP;
  56.     // Swap _egptr and _other_egptr.
  57.     tmp = _egptr; _egptr = _other_egptr; _other_egptr = tmp;
  58.     // Swap _gbase and _other_gbase.    
  59.     tmp = _eback; _eback = _other_gbase; _other_gbase = tmp;
  60.     _gptr = _egptr;
  61. }
  62.  
  63. int streambuf::switch_to_get_mode()
  64. {
  65.     if (_pptr > _pbase)
  66.     if (overflow(EOF) == EOF)
  67.         return EOF;
  68.     if (in_backup()) {
  69.     _eback = _aux_limit;
  70.     }
  71.     else {
  72.     _eback = _base;
  73.     if (_pptr > _egptr)
  74.         _egptr = _pptr;
  75.     }
  76.     _gptr = _pptr;
  77.  
  78.     setp(_gptr, _gptr);
  79.  
  80.     _flags &= ~_S_CURRENTLY_PUTTING;
  81.     return 0;
  82. }
  83.  
  84. void streambuf::free_backup_area()
  85. {
  86.     if (in_backup())
  87.     switch_to_main_get_area();  // Just in case.
  88.     delete [] _other_gbase;
  89.     _other_gbase = NULL;
  90.     _other_egptr = NULL;
  91.     _aux_limit = NULL;
  92. }
  93.  
  94. #if 0
  95. int streambuf::switch_to_put_mode()
  96. {
  97.     _pbase = _gptr;
  98.     _pptr = _gptr;
  99.     _epptr = in_backup() ? _egptr : _ebuf; // wrong if line- or un-buffered?
  100.  
  101.     _gptr = _egptr;
  102.     _eback = _egptr;
  103.  
  104.     _flags |= _S_CURRENTLY_PUTTING;
  105.     return 0;
  106. }
  107. #endif
  108.  
  109. #ifdef _G_FRIEND_BUG
  110. int __underflow(register streambuf *sb) { return __UNDERFLOW(sb); }
  111. int __UNDERFLOW(register streambuf *sb)
  112. #else
  113. int __underflow(register streambuf *sb)
  114. #endif
  115. {
  116.     if (sb->put_mode())
  117.         if (sb->switch_to_get_mode() == EOF) return EOF;
  118.     if (sb->_gptr < sb->_egptr)
  119.     return *(unsigned char*)sb->_gptr;
  120.     if (sb->in_backup()) {
  121.     sb->switch_to_main_get_area();
  122.     if (sb->_gptr < sb->_egptr)
  123.         return *sb->_gptr;
  124.     }
  125.     if (sb->have_markers()) {
  126.     // Append [_gbase.._egptr] to backup area.
  127.     long least_mark = sb->_least_marker();
  128.     // needed_size is how much space we need in the backup area.
  129.     long needed_size = (sb->_egptr - sb->_eback) - least_mark;
  130.     long current_Bsize = sb->_other_egptr - sb->_other_gbase;
  131.     long avail; // Extra space available for future expansion.
  132.     if (needed_size > current_Bsize) {
  133.         avail = 0; // 100 ?? FIXME
  134.         char *new_buffer = new char[avail+needed_size];
  135.         if (least_mark < 0) {
  136.         memcpy(new_buffer + avail,
  137.                sb->_other_egptr + least_mark,
  138.                -least_mark);
  139.         memcpy(new_buffer +avail - least_mark,
  140.                sb->_eback,
  141.                sb->_egptr - sb->_eback);
  142.         }
  143.         else
  144.         memcpy(new_buffer + avail,
  145.                sb->_eback + least_mark,
  146.                needed_size);
  147.         delete [] sb->_other_gbase;
  148.         sb->_other_gbase = new_buffer;
  149.         sb->_other_egptr = new_buffer + avail + needed_size;
  150.     }
  151.     else {
  152.         avail = current_Bsize - needed_size;
  153.         if (least_mark < 0) {
  154.         memmove(sb->_other_gbase + avail,
  155.             sb->_other_egptr + least_mark,
  156.             -least_mark);
  157.         memcpy(sb->_other_gbase + avail - least_mark,
  158.                sb->_eback,
  159.                sb->_egptr - sb->_eback);
  160.         }
  161.         else if (needed_size > 0)
  162.         memcpy(sb->_other_gbase + avail,
  163.                sb->_eback + least_mark,
  164.                needed_size);
  165.     }
  166.     // FIXME: Dubious arithmetic if pointers are NULL
  167.     sb->_aux_limit = sb->_other_gbase + avail;
  168.     // Adjust all the streammarkers.
  169.     long delta = sb->_egptr - sb->_eback;
  170.     for (register streammarker *mark = sb->_markers;
  171.          mark != NULL; mark = mark->_next)
  172.         mark->_pos -= delta;
  173.     }
  174.     else if (sb->have_backup())
  175.     sb->free_backup_area();
  176.     return sb->underflow();
  177. }
  178.  
  179. #ifdef _G_FRIEND_BUG
  180. int __overflow(register streambuf *sb, int c) { return __OVERFLOW(sb, c); }
  181. int __OVERFLOW(register streambuf *sb, int c)
  182. #else
  183. int __overflow(streambuf* sb, int c)
  184. #endif
  185. {
  186.     return sb->overflow(c);
  187. }
  188.  
  189. #ifdef atarist
  190. // for the atari we take a hit here so that bin/text modes are taken care of
  191. // automatically by sputc/sbumpc
  192.  
  193. size_t streambuf::sputn(const char* s, size_t n) // OPTIMIZE THIS!
  194. {
  195.     size_t count = 0;
  196.  
  197.     if(((long)n) < 0) return 0;
  198.  
  199.     for (; count < n; count++) {
  200.     if (sputc(*s++) == EOF)
  201.         break;
  202.     }
  203.     return count;
  204. }
  205.  
  206. size_t streambuf::sgetn(char* s, size_t n) // OPTIMIZE THIS!
  207. {
  208.     size_t count = 0;
  209.     for (; count < n; count++) {
  210.     int ch = sbumpc();
  211.     if (ch == EOF)
  212.         break;
  213.     *s++ = ch;
  214.     }
  215.     return count;
  216. }
  217.  
  218. size_t streambuf::ignore(size_t n)
  219. {
  220.     size_t more = n;
  221.     int ch;
  222.  
  223.     while(more && ((ch = sbumpc() != EOF))) more--;
  224.     return n - more;
  225. }
  226.  
  227. #else
  228. size_t streambuf::sputn(register const char* s, size_t n)
  229. {
  230.     if (n <= 0)
  231.     return 0;
  232.     register size_t more = n;
  233.     for (;;) {
  234.     size_t count = _epptr - _pptr; // Space available.
  235.     if (count > 0) {
  236.         if (count > more)
  237.         count = more;
  238.         if (count > 20) {
  239.         memcpy(_pptr, s, count);
  240.         s += count;
  241.         _pptr += count;
  242.         }
  243.         else if (count <= 0)
  244.         count = 0;
  245.         else {
  246.         register char *p = _pptr;
  247.         for (register long i = count; --i >= 0; ) *p++ = *s++;
  248.         _pptr = p;
  249.         }
  250.         more -= count;
  251.     }
  252.     if (more == 0 || __overflow(this, (unsigned char)*s++) == EOF)
  253.         break;
  254.     more--;
  255.     }
  256.     return n - more;
  257. }
  258.  
  259.  
  260. size_t streambuf::sgetn(char* s, size_t n)
  261. {
  262.     register size_t more = n;
  263.     for (;;) {
  264.     size_t count = _egptr - _gptr; // Data available.
  265.     if (count > 0) {
  266.         if (count > more)
  267.         count = more;
  268.         if (count > 20) {
  269.         memcpy(s, _gptr, count);
  270.         s += count;
  271.         _gptr += count;
  272.         }
  273.         else if (count <= 0)
  274.         count = 0;
  275.         else {
  276.         register char *p = _gptr;
  277.         for (register long i = count; --i >= 0; ) *s++ = *p++;
  278.         _gptr = p;
  279.         }
  280.         more -= count;
  281.     }
  282.     if (more == 0 || __underflow(this) == EOF)
  283.         break;
  284.     }
  285.     return n - more;
  286. }
  287.  
  288. size_t streambuf::ignore(size_t n)
  289. {
  290.     register size_t more = n;
  291.     for (;;) {
  292.     long count = _egptr - _gptr; // Data available.
  293.     if (count > 0) {
  294.         if (count > more)
  295.         count = more;
  296.         _gptr += count;
  297.         more -= count;
  298.     }
  299.     if (more == 0 || __underflow(this) == EOF)
  300.         break;
  301.     }
  302.     return n - more;
  303. }
  304. #endif /* atari */
  305.  
  306. int streambuf::padn(char pad, int count)
  307. {
  308. #define PADSIZE 16
  309.     static char const blanks[PADSIZE] =
  310.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  311.     static char const zeroes[PADSIZE] =
  312.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  313.     char padbuf[PADSIZE];
  314.     const char *padptr;
  315.     register int i;
  316.     
  317.     if (pad == ' ')
  318.     padptr = blanks;
  319.     else if (pad == '0')
  320.     padptr = zeroes;
  321.     else {
  322.     for (i = PADSIZE; --i >= 0; ) padbuf[i] = pad;
  323.     padptr = padbuf;
  324.     }
  325.     for (i = count; i >= PADSIZE; i -= PADSIZE)
  326.     if (sputn(padptr, PADSIZE) != PADSIZE)
  327.         return EOF;
  328.     if (i > 0 && sputn(padptr, i) != i)
  329.     return EOF;
  330.     return pad;
  331. }
  332.  
  333. int streambuf::sync()
  334. {
  335.     if (gptr() == egptr() && pptr() == pbase())
  336.     return 0;
  337.     return EOF;
  338. }
  339.  
  340. int streambuf::pbackfail(int c)
  341. {
  342.     return EOF;
  343. }
  344.  
  345. int streambuf::ungetfail()
  346. {
  347.     if (seekoff(-1, ios::cur, ios::in) == EOF)
  348.     return EOF;
  349.     return sgetc();
  350. }
  351.  
  352. streambuf* streambuf::setbuf(char* p, size_t len)
  353. {
  354.     if (sync() == EOF)
  355.     return NULL;
  356.     if (p == NULL || len == 0) {
  357.     unbuffered(1);
  358.     setb(_shortbuf, _shortbuf+1, 0);
  359.     }
  360.     else {
  361.     unbuffered(0);
  362.     setb(p, p+len, 0);
  363.     }
  364.     setp(0, 0);
  365.     setg(0, 0, 0);
  366.     return this;
  367. }
  368.  
  369. streampos streambuf::seekpos(streampos pos, int mode)
  370. {
  371.     return seekoff(pos, ios::beg, mode);
  372. }
  373.  
  374. void streambuf::setb(char* b, char* eb, int a)
  375. {
  376.     if (_base && !(_flags & _S_USER_BUF))
  377.     FREE_BUF(_base);
  378.     _base = b;
  379.     _ebuf = eb;
  380.     if (a)
  381.     _flags &= ~_S_USER_BUF;
  382.     else
  383.     _flags |= _S_USER_BUF;
  384. }
  385.  
  386. #ifdef atarist
  387. extern "C" { extern unsigned long __DEFAULT_BUFSIZ__; }
  388.  
  389. int streambuf::doallocate()
  390. {
  391.     char *buf = malloc((size_t)__DEFAULT_BUFSIZ__);
  392.     if (buf == NULL)
  393.     return EOF;
  394.     setb(buf, buf+__DEFAULT_BUFSIZ__, 1);
  395.     return 1;
  396. }
  397. #else
  398. int streambuf::doallocate()
  399. {
  400.     char *buf = ALLOC_BUF(_G_BUFSIZ);
  401.     if (buf == NULL)
  402.     return EOF;
  403.     setb(buf, buf+_G_BUFSIZ, 1);
  404.     return 1;
  405. }
  406. #endif
  407.  
  408. void streambuf::doallocbuf()
  409. {
  410.     if (base() || (!unbuffered() && doallocate() != EOF)) return;
  411.     setb(_shortbuf, _shortbuf+1, 0);
  412. }
  413.  
  414. #ifdef atarist
  415. extern "C" extern int __default_mode__;
  416. #endif
  417.  
  418. streambuf::streambuf(long flags)
  419. {
  420. #ifdef atarist
  421.   if(!(flags & _IOS_TEXT))
  422.       _flags = _IO_MAGIC | ((__default_mode__)? _S_IS_BINARY : 0) | flags;
  423.   else
  424.       _flags = _IO_MAGIC | (flags & (~_S_IS_BINARY));
  425. #else
  426.   _flags = _IO_MAGIC|flags;
  427. #endif
  428.   _base = NULL;
  429.   _ebuf = NULL;
  430.   _eback = NULL;
  431.   _gptr = NULL;
  432.   _egptr = NULL;
  433.   _pbase = NULL;
  434.   _pptr = NULL;
  435.   _epptr = NULL;
  436.   _chain = NULL; // Not necessary.
  437.  
  438.   _other_gbase = NULL;
  439.   _aux_limit = NULL;
  440.   _other_egptr = NULL;
  441.   _markers = NULL;
  442.   _cur_column = 0;
  443. }
  444.  
  445. streambuf::~streambuf()
  446. {
  447.     if (_base && !(_flags & _S_USER_BUF))
  448.     FREE_BUF(_base);
  449.  
  450.     for (register streammarker *mark = _markers;
  451.      mark != NULL; mark = mark->_next)
  452.     mark->_sbuf = NULL;
  453.     
  454. }
  455.  
  456. streampos
  457. streambuf::seekoff(streamoff, _seek_dir, int mode /*=ios::in|ios::out*/)
  458. {
  459.     return EOF;
  460. }
  461.  
  462. int streambuf::sputbackc(char c)
  463. {
  464.     if (gptr() <= eback()) return pbackfail(c);
  465.     gbump(-1);
  466.     // Don't write into the get buffer if we don't have to.
  467.     if (*gptr() != c)
  468.     *gptr() = c;
  469.     return (unsigned char)c;
  470. }
  471.  
  472. int streambuf::sungetc()
  473. {
  474.     if (gptr() > eback()) {
  475.     gbump(-1);
  476.     return (unsigned char)*gptr();
  477.     }
  478.     else
  479.     return ungetfail();
  480. }
  481.  
  482. #if 0 /* Work in progress */
  483. void streambuf::collumn(int c)
  484. {
  485.     if (c == -1)
  486.     _collumn = -1;
  487.     else
  488.     _collumn = c - (_pptr - _pbase);
  489. }
  490. #endif
  491.  
  492.  
  493. int streambuf::get_column()
  494. {
  495.     if (_cur_column) 
  496.     return __adjust_column(_cur_column - 1, pbase(), pptr() - pbase());
  497.     return -1;
  498. }
  499.  
  500. int streambuf::set_column(int i)
  501. {
  502.     overflow(EOF);
  503.     _cur_column = i+1;
  504.     return 0;
  505. }
  506.  
  507. int streambuf::flush_all()
  508. {
  509.     int result = 0;
  510.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  511.     if (sb->overflow(EOF) == EOF)
  512.         result = EOF;
  513.     return result;
  514. }
  515.  
  516. void streambuf::flush_all_linebuffered()
  517. {
  518.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  519.     if (sb->linebuffered())
  520.         sb->overflow(EOF);
  521. }
  522.  
  523. int backupbuf::underflow()
  524. {
  525.     return EOF;
  526. }
  527.  
  528. int backupbuf::overflow(int c)
  529. {
  530.     return EOF;
  531. }
  532.  
  533. streammarker::streammarker(streambuf *sb)
  534. {
  535.     _sbuf = sb;
  536.     if (!(sb->xflags() & _S_IS_BACKUPBUF)) {
  537.     set_streampos(sb->seekoff(0, ios::cur, ios::in));
  538.     _next = 0;
  539.     }
  540.     else {
  541.     if (sb->put_mode())
  542.         sb->switch_to_get_mode();
  543.     if (((backupbuf*)sb)->in_backup())
  544.         set_offset(sb->_gptr - sb->_egptr);
  545.     else
  546.         set_offset(sb->_gptr - sb->_eback);
  547.  
  548.     // Should perhaps sort the chain?
  549.     _next = ((backupbuf*)sb)->_markers;
  550.     ((backupbuf*)sb)->_markers = this;
  551.     }
  552. }
  553.  
  554. streammarker::~streammarker()
  555. {
  556.     if (saving()) {
  557.     // Unlink from sb's chain.
  558.     register streammarker **ptr = &((backupbuf*)_sbuf)->_markers;
  559.     for (; ; ptr = &(*ptr)->_next)
  560.         if (*ptr == NULL)
  561.         break;
  562.         else if (*ptr == this) {
  563.         *ptr = _next;
  564.         return;
  565.         }
  566.     }
  567. #if 0
  568.     if _sbuf has a backup area that is no longer needed, should we delete
  569.     it now, or wait until underflow()?
  570. #endif
  571. }
  572.  
  573. #define BAD_DELTA EOF
  574.  
  575. int streammarker::delta(streammarker& other_mark)
  576. {
  577.     if (_sbuf != other_mark._sbuf)
  578.     return BAD_DELTA;
  579.     if (saving() && other_mark.saving())
  580.     return _pos - other_mark._pos;
  581.     else if (!saving() && !other_mark.saving())
  582.     return _spos - other_mark._spos;
  583.     else
  584.     return BAD_DELTA;
  585. }
  586.  
  587. int streammarker::delta()
  588. {
  589.     if (_sbuf == NULL)
  590.     return BAD_DELTA;
  591.     if (saving()) {
  592.     int cur_pos;
  593.     if (_sbuf->in_backup())
  594.         cur_pos = _sbuf->_gptr - _sbuf->_egptr;
  595.     else
  596.         cur_pos = _sbuf->_gptr - _sbuf->_eback;
  597.     return _pos - cur_pos;
  598.     }
  599.     else {
  600.     if (_spos == EOF)
  601.         return BAD_DELTA;
  602.     int cur_pos = _sbuf->seekoff(0, ios::cur);
  603.     if (cur_pos == EOF)
  604.         return BAD_DELTA;
  605.     return _pos - cur_pos;
  606.     }
  607. }
  608.  
  609. int streambuf::seekmark(streammarker& mark, int delta = 0)
  610. {
  611.     if (mark._sbuf != this)
  612.     return EOF;
  613.     if (!mark.saving()) {
  614.     return seekpos(mark._spos, ios::in);
  615.     }
  616.     else if (mark._pos >= 0) {
  617.     if (in_backup())
  618.         switch_to_main_get_area();
  619.     _gptr = _eback + mark._pos;
  620.     }
  621.     else {
  622.     if (!in_backup())
  623.         switch_to_backup_area();
  624.     _gptr = _egptr + mark._pos;
  625.     }
  626.     return 0;
  627. }
  628.  
  629. void streambuf::unsave_markers()
  630. {
  631.     register streammarker *mark =_markers;
  632.     if (_markers) {
  633.     streampos offset = seekoff(0, ios::cur, ios::in);
  634.     if (offset != EOF) {
  635.         offset += eGptr() - Gbase();
  636.         for ( ; mark != NULL; mark = mark->_next)
  637.         mark->set_streampos(mark->_pos + offset);
  638.     }
  639.     else {
  640.         for ( ; mark != NULL; mark = mark->_next)
  641.         mark->set_streampos(EOF);
  642.     }
  643.     _markers = 0;
  644.     }
  645.  
  646.     free_backup_area();
  647. }
  648.  
  649. int backupbuf::pbackfail(int c)
  650. {
  651.     // Need to handle a filebuf in write mode (switch to read mode).  FIXME!
  652.  
  653.     if (have_backup() && !in_backup()) {
  654.     switch_to_backup_area();
  655.     }
  656.     if (!have_backup()) {
  657.     // No backup buffer: allocate one.
  658.     // Use short buffer, if unused? (probably not)  FIXME 
  659.     int backup_size = 128;
  660.     _other_gbase = new char [backup_size];
  661.     _other_egptr = _other_gbase + backup_size;
  662.     _aux_limit = _other_egptr;
  663.     switch_to_backup_area();
  664.     }
  665.     else if (gptr() <= eback()) {
  666.     // Increase size of existing backup buffer.
  667.     size_t new_size;
  668.     size_t old_size = egptr() - eback();
  669.     new_size = 2 * old_size;
  670.     char* new_buf = new char [new_size];
  671.     memcpy(new_buf+(new_size-old_size), eback(), old_size);
  672.     delete [] eback();
  673.     setg(new_buf, new_buf+(new_size-old_size), new_buf+new_size);
  674.     _aux_limit = _gptr;
  675.     }
  676.     gbump(-1);
  677.     if (*gptr() != c)
  678.     *gptr() = c;
  679.     return (unsigned char)c;
  680. }
  681.  
  682. unsigned __adjust_column(unsigned start, const char *line, int count)
  683. {
  684.     register const char *ptr = line + count;
  685.     while (ptr > line)
  686.     if (*--ptr == '\n')
  687.         return line + count - ptr - 1;
  688.     return start + count;
  689. }
  690.  
  691.  
  692. #if defined(linux)
  693. #define IO_CLEANUP ;
  694. #endif
  695.  
  696. #ifdef IO_CLEANUP
  697.   IO_CLEANUP
  698. #else
  699. struct __io_defs {
  700.     __io_defs() { }
  701.     ~__io_defs() { streambuf::flush_all(); }
  702. };   
  703. __io_defs io_defs__;
  704. #endif
  705.